From d858f3b514e0ec8911d209e597ce345288fea690 Mon Sep 17 00:00:00 2001 From: Tim Evans Date: Sun, 14 Dec 2003 01:06:56 +0000 Subject: [PATCH] Implement gdk_window_set_icon_list() for Win32, with support for big and Tue Dec 8 09:41:00 2003 Tim Evans * gdk/win32/gdkwindow-win32.[ch]: Implement gdk_window_set_icon_list() for Win32, with support for big and small icons and support for alpha-channel icons under Windows XP. Replaces the previous implementation of gdk_window_set_icon(). (#128762) --- ChangeLog | 8 + ChangeLog.pre-2-10 | 8 + ChangeLog.pre-2-4 | 8 + ChangeLog.pre-2-6 | 8 + ChangeLog.pre-2-8 | 8 + gdk/win32/gdkwindow-win32.c | 389 +++++++++++++++++++++++++++--------- gdk/win32/gdkwindow-win32.h | 3 +- 7 files changed, 337 insertions(+), 95 deletions(-) diff --git a/ChangeLog b/ChangeLog index 331ed52938..5409d88c3b 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,11 @@ +Tue Dec 8 09:41:00 2003 Tim Evans + + * gdk/win32/gdkwindow-win32.[ch]: Implement + gdk_window_set_icon_list() for Win32, with support for big and + small icons and support for alpha-channel icons under Windows + XP. Replaces the previous implementation of gdk_window_set_icon(). + (#128762) + Sun Dec 14 01:28:23 2003 Matthias Clasen * gdk/x11/gdkprivate-x11.h: diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 331ed52938..5409d88c3b 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,3 +1,11 @@ +Tue Dec 8 09:41:00 2003 Tim Evans + + * gdk/win32/gdkwindow-win32.[ch]: Implement + gdk_window_set_icon_list() for Win32, with support for big and + small icons and support for alpha-channel icons under Windows + XP. Replaces the previous implementation of gdk_window_set_icon(). + (#128762) + Sun Dec 14 01:28:23 2003 Matthias Clasen * gdk/x11/gdkprivate-x11.h: diff --git a/ChangeLog.pre-2-4 b/ChangeLog.pre-2-4 index 331ed52938..5409d88c3b 100644 --- a/ChangeLog.pre-2-4 +++ b/ChangeLog.pre-2-4 @@ -1,3 +1,11 @@ +Tue Dec 8 09:41:00 2003 Tim Evans + + * gdk/win32/gdkwindow-win32.[ch]: Implement + gdk_window_set_icon_list() for Win32, with support for big and + small icons and support for alpha-channel icons under Windows + XP. Replaces the previous implementation of gdk_window_set_icon(). + (#128762) + Sun Dec 14 01:28:23 2003 Matthias Clasen * gdk/x11/gdkprivate-x11.h: diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 331ed52938..5409d88c3b 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,3 +1,11 @@ +Tue Dec 8 09:41:00 2003 Tim Evans + + * gdk/win32/gdkwindow-win32.[ch]: Implement + gdk_window_set_icon_list() for Win32, with support for big and + small icons and support for alpha-channel icons under Windows + XP. Replaces the previous implementation of gdk_window_set_icon(). + (#128762) + Sun Dec 14 01:28:23 2003 Matthias Clasen * gdk/x11/gdkprivate-x11.h: diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 331ed52938..5409d88c3b 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,3 +1,11 @@ +Tue Dec 8 09:41:00 2003 Tim Evans + + * gdk/win32/gdkwindow-win32.[ch]: Implement + gdk_window_set_icon_list() for Win32, with support for big and + small icons and support for alpha-channel icons under Windows + XP. Replaces the previous implementation of gdk_window_set_icon(). + (#128762) + Sun Dec 14 01:28:23 2003 Matthias Clasen * gdk/x11/gdkprivate-x11.h: diff --git a/gdk/win32/gdkwindow-win32.c b/gdk/win32/gdkwindow-win32.c index 7f28f8ae0c..7398500611 100644 --- a/gdk/win32/gdkwindow-win32.c +++ b/gdk/win32/gdkwindow-win32.c @@ -35,8 +35,40 @@ #include "gdkprivate-win32.h" #include "gdkinput-win32.h" +#ifdef __MINGW32__ +typedef struct { + DWORD bV5Size; + LONG bV5Width; + LONG bV5Height; + WORD bV5Planes; + WORD bV5BitCount; + DWORD bV5Compression; + DWORD bV5SizeImage; + LONG bV5XPelsPerMeter; + LONG bV5YPelsPerMeter; + DWORD bV5ClrUsed; + DWORD bV5ClrImportant; + DWORD bV5RedMask; + DWORD bV5GreenMask; + DWORD bV5BlueMask; + DWORD bV5AlphaMask; + DWORD bV5CSType; + CIEXYZTRIPLE bV5Endpoints; + DWORD bV5GammaRed; + DWORD bV5GammaGreen; + DWORD bV5GammaBlue; + DWORD bV5Intent; + DWORD bV5ProfileData; + DWORD bV5ProfileSize; + DWORD bV5Reserved; +} BITMAPV5HEADER; + +#endif + +#if 0 #include -#include /* sprintf */ +#include +#endif static GdkColormap* gdk_window_impl_win32_get_colormap (GdkDrawable *drawable); static void gdk_window_impl_win32_set_colormap (GdkDrawable *drawable, @@ -92,7 +124,8 @@ gdk_window_impl_win32_init (GdkWindowImplWin32 *impl) impl->height = 1; impl->hcursor = NULL; - impl->hicon = NULL; + impl->hicon_big = NULL; + impl->hicon_small = NULL; impl->hint_flags = 0; impl->extension_events_selected = FALSE; } @@ -142,10 +175,15 @@ gdk_window_impl_win32_finalize (GObject *object) GDI_CALL (DestroyCursor, (window_impl->hcursor)); window_impl->hcursor = NULL; } - if (window_impl->hicon != NULL) + if (window_impl->hicon_big != NULL) + { + GDI_CALL (DestroyIcon, (window_impl->hicon_big)); + window_impl->hicon_big = NULL; + } + if (window_impl->hicon_small != NULL) { - GDI_CALL (DestroyIcon, (window_impl->hicon)); - window_impl->hicon = NULL; + GDI_CALL (DestroyIcon, (window_impl->hicon_small)); + window_impl->hicon_small = NULL; } G_OBJECT_CLASS (parent_class)->finalize (object); @@ -2169,121 +2207,284 @@ gdk_window_set_accept_focus (GdkWindow *window, private->accept_focus = accept_focus; } -void -gdk_window_set_icon_list (GdkWindow *window, - GList *pixbufs) +static HICON +pixbuf_to_hicon_alpha_winxp (GdkWindow *window, + GdkPixbuf *pixbuf) { - g_return_if_fail (GDK_IS_WINDOW (window)); + /* Based on code from + * http://www.dotnet247.com/247reference/msgs/13/66301.aspx + */ + HDC hdc; + BITMAPV5HEADER bi; + HBITMAP hBitmap, hMonoBitmap; + guchar *indata, *inrow; + guchar *outdata, *outrow; + HICON hAlphaIcon = NULL; + ICONINFO ii; + gint width, height, i, j, rowstride; - if (GDK_WINDOW_DESTROYED (window)) - return; + if (pixbuf == NULL) + return NULL; - /* We could convert it to a hIcon and DrawIcon () it when getting - * a WM_PAINT with IsIconic, but is it worth it ? Same probably - * goes for gdk_window_set_icon (). Patches accepted :-) --hb - * Or do we only need to deliver the Icon on WM_GETICON ? + width = gdk_pixbuf_get_width (pixbuf); /* width of icon */ + height = gdk_pixbuf_get_height (pixbuf); /* height of icon */ + + ZeroMemory (&bi, sizeof (BITMAPV5HEADER)); + bi.bV5Size = sizeof (BITMAPV5HEADER); + bi.bV5Width = width; + bi.bV5Height = height; + bi.bV5Planes = 1; + bi.bV5BitCount = 32; + bi.bV5Compression = BI_BITFIELDS; + /* The following mask specification specifies a supported 32 BPP + * alpha format for Windows XP (BGRA format). */ + bi.bV5RedMask = 0x00FF0000; + bi.bV5GreenMask = 0x0000FF00; + bi.bV5BlueMask = 0x000000FF; + bi.bV5AlphaMask = 0xFF000000; + + /* Create the DIB section with an alpha channel. */ + hdc = GetDC (NULL); + hBitmap = CreateDIBSection (hdc, (BITMAPINFO *)&bi, DIB_RGB_COLORS, + (void **)&outdata, NULL, (DWORD)0); + ReleaseDC (NULL, hdc); + + /* Draw something on the DIB section */ + indata = gdk_pixbuf_get_pixels (pixbuf); + rowstride = gdk_pixbuf_get_rowstride (pixbuf); + for (j=0; jimpl); + if (pixbuf == NULL) + return NULL; - if (pixmap) - { - static int num = 0; - HBITMAP hbmmask = NULL; + /* create a normal icon with a bitmap mask */ + w = gdk_pixbuf_get_width (pixbuf); + h = gdk_pixbuf_get_height (pixbuf); + gdk_pixbuf_render_pixmap_and_mask_for_colormap (pixbuf, + gdk_drawable_get_colormap (window), + &pixmap, + &mask, + 128); - gdk_drawable_get_size (GDK_DRAWABLE(pixmap), &w, &h); + /* we need the inverted mask for the XOR op */ + { + HDC hdc1 = CreateCompatibleDC (NULL); + HBITMAP hbmold1; - /* we need the inverted mask for the XOR op */ + hbmmask = CreateCompatibleBitmap (hdc1, w, h); + hbmold1 = SelectObject (hdc1, hbmmask); + if (mask) + { + HDC hdc2 = CreateCompatibleDC (NULL); + HBITMAP hbmold2 = SelectObject (hdc2, GDK_PIXMAP_HBITMAP (mask)); + GDI_CALL (BitBlt, (hdc1, 0,0,w,h, hdc2, 0,0, NOTSRCCOPY)); + GDI_CALL (SelectObject, (hdc2, hbmold2)); + GDI_CALL (DeleteDC, (hdc2)); + } + else { - HDC hdc1 = CreateCompatibleDC (NULL); - HBITMAP hbmold1; - - hbmmask = CreateCompatibleBitmap (hdc1, w, h); - hbmold1 = SelectObject (hdc1, hbmmask); - if (mask) - { - HDC hdc2 = CreateCompatibleDC (NULL); - HBITMAP hbmold2 = SelectObject (hdc2, GDK_PIXMAP_HBITMAP (mask)); - GDI_CALL (BitBlt, (hdc1, 0,0,w,h, hdc2, 0,0, NOTSRCCOPY)); - GDI_CALL (SelectObject, (hdc2, hbmold2)); - GDI_CALL (DeleteDC, (hdc2)); - } - else - { - RECT rect; - GetClipBox (hdc1, &rect); - GDI_CALL (FillRect, (hdc1, &rect, GetStockObject (WHITE_BRUSH))); - } - GDI_CALL (SelectObject, (hdc1, hbmold1)); - GDI_CALL (DeleteDC, (hdc1)); + RECT rect; + GetClipBox (hdc1, &rect); + GDI_CALL (FillRect, (hdc1, &rect, GetStockObject (BLACK_BRUSH))); } + GDI_CALL (SelectObject, (hdc1, hbmold1)); + GDI_CALL (DeleteDC, (hdc1)); + } + + ii.fIcon = TRUE; + ii.xHotspot = ii.yHotspot = 0; /* ignored for icons */ + ii.hbmMask = hbmmask; + ii.hbmColor = GDK_PIXMAP_HBITMAP (pixmap); + hIcon = CreateIconIndirect (&ii); + if (!hIcon) + WIN32_API_FAILED ("CreateIconIndirect"); + GDI_CALL (DeleteObject, (hbmmask)); - ii.fIcon = TRUE; - ii.xHotspot = ii.yHotspot = 0; /* ignored for icons */ - ii.hbmMask = hbmmask; - ii.hbmColor = GDK_PIXMAP_HBITMAP (pixmap); - hIcon = CreateIconIndirect (&ii); - if (!hIcon) - WIN32_API_FAILED ("CreateIconIndirect"); - GDI_CALL (DeleteObject, (hbmmask)); #if 0 /* to debug pixmap and mask setting */ + { + static int num = 0; + GdkPixbuf* pixbuf = NULL; + char name[256]; + + pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0, w, h); + if (pixbuf) { - GdkPixbuf* pixbuf = NULL; - char name[256]; - - pixbuf = gdk_pixbuf_get_from_drawable (NULL, pixmap, NULL, 0, 0, 0, 0, w, h); - if (pixbuf) - { - num = (num + 1) % 999; /* restrict maximim number */ - sprintf (name, "c:\\temp\\ico%03dpixm.png", num); - gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL); - gdk_pixbuf_unref (pixbuf); - } - pixbuf = !mask ? NULL : gdk_pixbuf_get_from_drawable (NULL, mask, NULL, 0, 0, 0, 0, w, h); - if (pixbuf) - { - sprintf (name, "c:\\temp\\ico%03dmask.png", num); - gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL); - gdk_pixbuf_unref (pixbuf); - } + num = (num + 1) % 999; /* restrict maximim number */ + sprintf (name, "c:\\temp\\ico%03dpixm.png", num); + gdk_pixbuf_save (pixbuf, name, "png", NULL, NULL); + gdk_pixbuf_unref (pixbuf); } + } #endif - SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, (LPARAM)hIcon); - if (impl->hicon) - GDI_CALL (DestroyIcon, (impl->hicon)); - impl->hicon = hIcon; + if (pixmap) + g_object_unref (G_OBJECT (pixmap)); + if (mask) + g_object_unref (G_OBJECT (mask)); + + return hIcon; +} + +static HICON +pixbuf_to_hicon (GdkWindow *window, + GdkPixbuf *pixbuf) +{ + static gboolean is_win_xp=FALSE, is_win_xp_checked=FALSE; + + if (!is_win_xp_checked) + { + OSVERSIONINFO version; + + is_win_xp_checked = TRUE; + memset (&version, 0, sizeof (version)); + version.dwOSVersionInfoSize = sizeof (version); + is_win_xp = GetVersionEx (&version) + && version.dwPlatformId == VER_PLATFORM_WIN32_NT + && (version.dwMajorVersion > 5 + || (version.dwMajorVersion == 5 && version.dwMinorVersion >= 1)); } + + if (pixbuf == NULL) + return NULL; + + if (is_win_xp && gdk_pixbuf_get_has_alpha (pixbuf)) + return pixbuf_to_hicon_alpha_winxp (window, pixbuf); else - { - /* reseting to default icon */ - if (impl->hicon) - { - SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, 0); - GDI_CALL (DestroyIcon, (impl->hicon)); - impl->hicon = NULL; - } + return pixbuf_to_hicon_normal (window, pixbuf); +} + +void +gdk_window_set_icon_list (GdkWindow *window, + GList *pixbufs) +{ + GdkPixbuf *pixbuf, *big_pixbuf, *small_pixbuf; + gint big_diff, small_diff; + gint big_w, big_h, small_w, small_h; + gint w, h; + gint dw, dh, diff; + HICON small_hicon, big_hicon; + GdkWindowImplWin32 *impl; + gint i, big_i, small_i; + + g_return_if_fail (GDK_IS_WINDOW (window)); + + if (GDK_WINDOW_DESTROYED (window)) + return; + + impl = GDK_WINDOW_IMPL_WIN32 (GDK_WINDOW_OBJECT (window)->impl); + + /* ideal sizes for small and large icons */ + big_w = GetSystemMetrics (SM_CXICON); + big_h = GetSystemMetrics (SM_CYICON); + small_w = GetSystemMetrics (SM_CXSMICON); + small_h = GetSystemMetrics (SM_CYSMICON); + + /* find closest sized icons in the list */ + big_pixbuf = NULL; + small_pixbuf = NULL; + big_diff = 0; + small_diff = 0; + i = 0; + while (pixbufs) + { + pixbuf = (GdkPixbuf*) pixbufs->data; + w = gdk_pixbuf_get_width (pixbuf); + h = gdk_pixbuf_get_height (pixbuf); + + dw = ABS (w - big_w); + dh = ABS (h - big_h); + diff = dw*dw + dh*dh; + if (big_pixbuf == NULL || diff < big_diff) + { + big_pixbuf = pixbuf; + big_diff = diff; + big_i = i; + } + + dw = ABS(w - small_w); + dh = ABS(h - small_h); + diff = dw*dw + dh*dh; + if (small_pixbuf == NULL || diff < small_diff) + { + small_pixbuf = pixbuf; + small_diff = diff; + small_i = i; + } + + pixbufs = g_list_next (pixbufs); + i++; } - GDK_NOTE (MISC, g_print ("gdk_window_set_icon: %p: %p %dx%d\n", GDK_WINDOW_HWND (window), impl->hicon, w, h)); + /* Create the icons */ + big_hicon = pixbuf_to_hicon (window, big_pixbuf); + small_hicon = pixbuf_to_hicon (window, small_pixbuf); + + /* Set the icons */ + SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_BIG, + (LPARAM)big_hicon); + SendMessage (GDK_WINDOW_HWND (window), WM_SETICON, ICON_SMALL, + (LPARAM)small_hicon); + + /* Store the icons, destroying any previous icons */ + if (impl->hicon_big) + GDI_CALL (DestroyIcon, (impl->hicon_big)); + impl->hicon_big = big_hicon; + if (impl->hicon_small) + GDI_CALL (DestroyIcon, (impl->hicon_small)); + impl->hicon_small = small_hicon; +} + +void +gdk_window_set_icon (GdkWindow *window, + GdkWindow *icon_window, + GdkPixmap *pixmap, + GdkBitmap *mask) +{ + g_return_if_fail (window != NULL); + g_return_if_fail (GDK_IS_WINDOW (window)); + + /* do nothing, use gdk_window_set_icon_list instead */ } void diff --git a/gdk/win32/gdkwindow-win32.h b/gdk/win32/gdkwindow-win32.h index b2f07e79c2..6561b54e8e 100644 --- a/gdk/win32/gdkwindow-win32.h +++ b/gdk/win32/gdkwindow-win32.h @@ -76,7 +76,8 @@ struct _GdkWindowImplWin32 GdkWin32PositionInfo position_info; HCURSOR hcursor; - HICON hicon; + HICON hicon_big; + HICON hicon_small; /* Window size hints */ gint hint_flags; -- 2.30.2